package com.njtoyo.taxi.admin.service.business.ride.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njtoyo.taxi.admin.library.Const;
import com.njtoyo.taxi.admin.library.common.util.CopyUtil;
import com.njtoyo.taxi.admin.library.payment.cmb.CmbPayClient;
import com.njtoyo.taxi.admin.mapper.master.entity.CallPrepayOrder;
import com.njtoyo.taxi.admin.mapper.master.entity.CallPrepayOrderRefundLog;
import com.njtoyo.taxi.admin.mapper.master.entity.Ride;
import com.njtoyo.taxi.admin.mapper.master.entity.Taxi;
import com.njtoyo.taxi.admin.mapper.master.enums.RealtimeCallCategory;
import com.njtoyo.taxi.admin.mapper.master.enums.RideStateState;
import com.njtoyo.taxi.admin.mapper.master.mapper.*;
import com.njtoyo.taxi.admin.mongo.entity.primary.RealtimeCallMqttMsgMongo;
import com.njtoyo.taxi.admin.mongo.repository.primary.RealtimeCallMqttMsgMongoRepository;
import com.njtoyo.taxi.admin.rest.export.customer.NoResponseCustomerMobileNumberPresenter;
import com.njtoyo.taxi.admin.rest.presenter.business.ride.call.RealTimeSinglePagePresenter;
import com.njtoyo.taxi.admin.rest.presenter.business.ride.call.ReservationPagePresenter;
import com.njtoyo.taxi.admin.rest.presenter.platfrom.AdminUserIdentityPresenter;
import com.njtoyo.taxi.admin.rest.wrapper.business.call.NoResponseCustomerMobileNumberExportDto;
import com.njtoyo.taxi.admin.rest.wrapper.business.call.NoResponseCustomerMobileNumberExportWrapper;
import com.njtoyo.taxi.admin.rest.wrapper.business.ride.CallWrapper;
import com.njtoyo.taxi.admin.rest.wrapper.business.ride.CallWrapperDto;
import com.njtoyo.taxi.admin.service.business.ride.CallsService;
import com.njtoyo.taxi.admin.utils.StringUtils;
import com.taxi.entity.common.RestResult;
import com.njtoyo.taxi.entity.backend.AdminUser;
import com.njtoyo.taxi.entity.backend.Enum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@DS(Const.SECONDARY_DS)
public class CallsServiceImpl implements CallsService {

    @Autowired
    private AppointmentCallMapper appointmentCallMapper;

    @Autowired
    private RealtimeCallMapper realtimeCallMapper;

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private CallPrepayOrderMapper callPrepayOrderMapper;
    @Autowired
    private CallPrepayOrderRefundLogMapper callPrepayOrderRefundLogMapper;
    @Autowired
    private TaxiMapper taxiMapper;
    @Autowired
    private RealtimeCallMqttMsgMongoRepository realtimeCallMqttMsgMongoRepository;
    @Autowired
    private RideMapper rideMapper;

    @Autowired
    @Qualifier("primaryMongoTemplate")
    private MongoTemplate primaryMongoTemplate;

    /**
     * 呼叫订单身份校验
     */
    CallWrapper check(AdminUser adminUser, CallWrapper wrapper) {
        AdminUserIdentityPresenter identity = (AdminUserIdentityPresenter) adminUser.getIdentity();
        switch (adminUser.getAccountType()) {
            case canton:
            case company:
                wrapper.setCantonIds(identity.getCantonIds());
                break;
        }
        return wrapper;
    }

    /**
     * 实时单列表
     *
     * @param adminUser
     * @param wrapper
     * @return
     */
    @Override
    public RestResult<Page<RealTimeSinglePagePresenter>> realTimeSingleList(AdminUser adminUser, CallWrapper wrapper) {
        CallWrapper check = check(adminUser, wrapper);
        wrapper.setCategory(RealtimeCallCategory.realtime);
        if (StrUtil.isNotBlank(wrapper.getPlateNumber())) {
            //查询mq发送记录
            Taxi taxi = taxiMapper.selectOne(Wrappers.<Taxi>lambdaQuery().eq(Taxi::getPlateNumber, wrapper.getPlateNumber()));
            if (ObjectUtil.isNotNull(taxi)) {
                List<RealtimeCallMqttMsgMongo> list = realtimeCallMqttMsgMongoRepository.findByTaxiId(taxi.getId());
                if (CollUtil.isNotEmpty(list)) {
                    List<Long> callIds = list.stream().map(RealtimeCallMqttMsgMongo::getRealtimeCallId).distinct().collect(Collectors.toList());
                    wrapper.setCallIds(callIds);
                } else {
                    return RestResult.success(new Page<>());
                }
            }
        }
        if (StrUtil.isNotBlank(wrapper.getStartDate()) && StrUtil.isNotBlank(wrapper.getEndDate())) {
            wrapper.setStartDate(wrapper.getStartDate() + " 00:00:00");
            wrapper.setEndDate(wrapper.getEndDate() + " 23:59:59");
        }
        Page<RealTimeSinglePagePresenter> realTimeSingleList
                = realtimeCallMapper.selectCallPage(check);
        return RestResult.success(realTimeSingleList);
    }

    /**
     * 预约单列表
     *
     * @param adminUser
     * @param wrapper
     * @return
     */
    @Override
    public RestResult<Page<ReservationPagePresenter>> reservationList(AdminUser adminUser, CallWrapper wrapper) {
        CallWrapper check = check(adminUser, wrapper);
        if (StrUtil.isNotBlank(wrapper.getStartDate()) && StrUtil.isNotBlank(wrapper.getEndDate())) {
            wrapper.setStartDate(wrapper.getStartDate() + " 00:00:00");
            wrapper.setEndDate(wrapper.getEndDate() + " 23:59:59");
        }
        Page<ReservationPagePresenter> reservationListPresenterPage
                = appointmentCallMapper.selectAppointmentCallPage(check);
        return RestResult.success(reservationListPresenterPage);
    }

    /**
     * 指定单列表
     *
     * @param adminUser
     * @param wrapper
     * @return
     */
    @Override
    public RestResult<Page<RealTimeSinglePagePresenter>> specifiedList(AdminUser adminUser, CallWrapper wrapper) {
        CallWrapper check = check(adminUser, wrapper);
        wrapper.setCategory(RealtimeCallCategory.assign);
        if (StrUtil.isNotBlank(wrapper.getStartDate()) && StrUtil.isNotBlank(wrapper.getEndDate())) {
            wrapper.setStartDate(wrapper.getStartDate() + " 00:00:00");
            wrapper.setEndDate(wrapper.getEndDate() + " 23:59:59");
        }
        Page<RealTimeSinglePagePresenter> realTimeSingleListPresenterPage
                = realtimeCallMapper.selectCallPage(check);
        return RestResult.success(realTimeSingleListPresenterPage);
    }

    @Override
    public void getNoResponseCustomerMobileNumberExport(AdminUser adminUser, NoResponseCustomerMobileNumberExportWrapper wrapper, HttpServletResponse response) throws IOException {
        NoResponseCustomerMobileNumberExportDto dto = CopyUtil.copy(wrapper, NoResponseCustomerMobileNumberExportDto.class);

        if (!adminUser.getAccountType().equals(Enum.AccountType.platform)) {
            AdminUserIdentityPresenter identity = (AdminUserIdentityPresenter) adminUser.getIdentity();
            dto.setCustomerRegionIds(identity.getCustomerRegionIds());
        }

        // 校验数据量
        this.countNoResponseCustomerMobileNumber(dto);
        List<NoResponseCustomerMobileNumberPresenter> res = this.getNoResponseCustomerMobileNumber(dto);

        String fileName = URLEncoder.encode("无应答订单", "UTF-8").replaceAll("\\+", "%20");
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), NoResponseCustomerMobileNumberPresenter.class)
                .sheet(0)
                .doWrite(res);
    }

    @Override
    public RestResult refund(Long id, BigDecimal refundAmount) {
        CallPrepayOrder callPrepayOrder = callPrepayOrderMapper.selectOne(Wrappers.<CallPrepayOrder>lambdaQuery().eq(CallPrepayOrder::getCallId, id));
        if (ObjectUtil.isNull(callPrepayOrder)) {
            return RestResult.failed("退款失败,未查到预付信息");
        }
        List<RideStateState> notRefundStates = Arrays.asList(RideStateState.contracted, RideStateState.pickuping, RideStateState.started, RideStateState.inarea);
        Ride ride = rideMapper.selectOne((Wrappers.<Ride>lambdaQuery().eq(Ride::getRefId, id)));
        if (ObjectUtil.isNotNull(ride) && (ride.getState() == RideStateState.completed || ride.getState() == RideStateState.marked)) {
            return RestResult.failed("已完成的订单请到【订单管理】退款");
        } else if (ObjectUtil.isNotNull(ride) && notRefundStates.contains(ride.getState())) {
            return RestResult.failed("行程已开始无法退预付");
        }
        String refundId = IdUtil.getSnowflake(1, 1).nextIdStr();
        String preAmountStr = Convert.toStr(callPrepayOrder.getAmount().multiply(new BigDecimal(100)).intValue());
        String willRefundAmountStr = Convert.toStr(refundAmount.multiply(new BigDecimal(100)).intValue());
        Map<String, String> resultRefundAmount = CmbPayClient.refund(refundId, callPrepayOrder.getNumber(), "退款", callPrepayOrder.getNumber(), refundId, preAmountStr, willRefundAmountStr);
        String errCodeRefundAmount = MapUtil.getStr(resultRefundAmount, "errCode");
        if (StrUtil.isNotBlank(errCodeRefundAmount)) {
            String respMsg = MapUtil.getStr(resultRefundAmount, "respMsg");
            log.info("预付单：{},招商退预付款返回--失败,失败原因：{}", callPrepayOrder, respMsg);
            return RestResult.failed("退款失败,失败原因：" + respMsg);
        }
        String respPreCode = MapUtil.getStr(resultRefundAmount, "respCode");
        if ("SUCCESS".equals(respPreCode)) {
            log.info("预付单：{},招商退预付款返回--成功", callPrepayOrder);
            //保存预付款的退款记录
            callPrepayOrderRefundLogMapper.insert(new CallPrepayOrderRefundLog()
                    .setOrderId(callPrepayOrder.getId())
                    .setIsSuccess(true)
                    .setRefundAmount(refundAmount)
                    .setRefundNumber(callPrepayOrder.getNumber()));
            //修改预付款退款状态
            callPrepayOrderMapper.updateById(new CallPrepayOrder().setId(callPrepayOrder.getId()).setIsRefund(true));

            //
        }
        return RestResult.success();
    }

    @Override
    public void getRealTimeSingleListExport(AdminUser adminUser, CallWrapperDto wrapper, HttpServletResponse response) throws IOException {
        List<RealTimeSinglePagePresenter> realTimeSinglePagePresenterList = new ArrayList<>();

        AdminUserIdentityPresenter identity = (AdminUserIdentityPresenter) adminUser.getIdentity();
        switch (adminUser.getAccountType()) {
            case canton:
            case company:
                wrapper.setCantonIds(identity.getCantonIds());
                break;
        }
        wrapper.setCategory(RealtimeCallCategory.realtime);
        if (StrUtil.isNotBlank(wrapper.getPlateNumber())) {
            //查询mq发送记录
            Taxi taxi = taxiMapper.selectOne(Wrappers.<Taxi>lambdaQuery().eq(Taxi::getPlateNumber, wrapper.getPlateNumber()));
            if (ObjectUtil.isNotNull(taxi)) {
                List<RealtimeCallMqttMsgMongo> list = realtimeCallMqttMsgMongoRepository.findByTaxiId(taxi.getId());
                if (CollUtil.isNotEmpty(list)) {
                    List<Long> callIds = list.stream().map(RealtimeCallMqttMsgMongo::getRealtimeCallId).distinct().collect(Collectors.toList());
                    wrapper.setCallIds(callIds);
                } else {
                    EasyExcel.write(response.getOutputStream(), RealTimeSinglePagePresenter.class)
                            .sheet(0)
                            .doWrite(realTimeSinglePagePresenterList); ;
                }
            }
        }
        if (StrUtil.isNotBlank(wrapper.getStartDate()) && StrUtil.isNotBlank(wrapper.getEndDate())) {
            wrapper.setStartDate(wrapper.getStartDate() + " 00:00:00");
            wrapper.setEndDate(wrapper.getEndDate() + " 23:59:59");
        }else
        {
            //默认查询当天
            wrapper.setStartDate(DateUtil.format(DateUtil.beginOfDay(new Date()), "yyyy-MM-dd HH:mm:ss"));
            wrapper.setEndDate(DateUtil.format(DateUtil.endOfDay(new Date()), "yyyy-MM-dd HH:mm:ss"));
        }
        realTimeSinglePagePresenterList = realtimeCallMapper.selectCallListExport(wrapper);
        String fileName = URLEncoder.encode("实时单", "UTF-8").replaceAll("\\+", "%20");
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), RealTimeSinglePagePresenter.class)
                .sheet(0)
                .doWrite(realTimeSinglePagePresenterList);
    }

    @Override
    public void getReservationListExport(AdminUser adminUser, CallWrapperDto wrapper, HttpServletResponse response) throws IOException {
        AdminUserIdentityPresenter identity = (AdminUserIdentityPresenter) adminUser.getIdentity();
        switch (adminUser.getAccountType()) {
            case canton:
            case company:
                wrapper.setCantonIds(identity.getCantonIds());
                break;
        }
        if(StringUtils.isEmpty(wrapper.getStartDate()))
        {
            wrapper.setStartDate(DateUtil.format(DateUtil.beginOfDay(new Date()), "yyyy-MM-dd HH:mm:ss"));
            wrapper.setEndDate(DateUtil.format(DateUtil.endOfDay(new Date()), "yyyy-MM-dd HH:mm:ss"));
        }else{
            wrapper.setStartDate(wrapper.getStartDate() + " 00:00:00");
            wrapper.setEndDate(wrapper.getEndDate() + " 23:59:59");
        }
        List<ReservationPagePresenter> reservationPagePresenterList = appointmentCallMapper.selectAppointmentCallListExport(wrapper);
        String fileName = URLEncoder.encode("预约单", "UTF-8").replaceAll("\\+", "%20");
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), ReservationPagePresenter.class)
                .sheet().doWrite(reservationPagePresenterList);
    }

    @Override
    public void getSpecifiedListExport(AdminUser adminUser, CallWrapperDto wrapper, HttpServletResponse response) throws IOException {
        AdminUserIdentityPresenter identity = (AdminUserIdentityPresenter) adminUser.getIdentity();
        switch (adminUser.getAccountType()) {
            case canton:
            case company:
                wrapper.setCantonIds(identity.getCantonIds());
                break;
        }
        wrapper.setCategory(RealtimeCallCategory.assign);
        if (StrUtil.isNotBlank(wrapper.getStartDate()) && StrUtil.isNotBlank(wrapper.getEndDate())) {
            wrapper.setStartDate(wrapper.getStartDate() + " 00:00:00");
            wrapper.setEndDate(wrapper.getEndDate() + " 23:59:59");
        }else
        {
            //默认查询当天
            wrapper.setStartDate(DateUtil.format(DateUtil.beginOfDay(new Date()), "yyyy-MM-dd HH:mm:ss"));
            wrapper.setEndDate(DateUtil.format(DateUtil.endOfDay(new Date()), "yyyy-MM-dd HH:mm:ss"));
        }
        List<RealTimeSinglePagePresenter> realTimeSinglePagePresenters = realtimeCallMapper.selectCallListExport(wrapper);
        String fileName = URLEncoder.encode("指定单", "UTF-8").replaceAll("\\+", "%20");
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), RealTimeSinglePagePresenter.class)
                .sheet()
                .doWrite(realTimeSinglePagePresenters);
    }

    private RestResult<Object> countNoResponseCustomerMobileNumber(NoResponseCustomerMobileNumberExportDto wrapper) {
        Long count = userMapper.countNoResponseCustomerMobileNumber(wrapper);
        if (count > 5000) {
            return RestResult.failed("数据量过大,请缩小筛选范围再导出");
        }
        return null;
    }

    private List<NoResponseCustomerMobileNumberPresenter> getNoResponseCustomerMobileNumber(NoResponseCustomerMobileNumberExportDto wrapper) {
        return userMapper.getNoResponseCustomerMobileNumber(wrapper);
    }

    public static void main(String[] args) {
        String format = DateUtil.format(DateUtil.beginOfDay(new Date()), "yyyy-MM-dd HH:mm:ss");
        System.out.println(format);
        String format2 = DateUtil.format(DateUtil.endOfDay(new Date()), "yyyy-MM-dd HH:mm:ss");
        System.out.println(format2);
    }
}
